"""密钥轮换提醒系统。"""

import asyncio
from typing import Dict, List, Optional, Any
from datetime import datetime, timedelta
from dataclasses import dataclass
from enum import Enum
import motor.motor_asyncio
from bson import ObjectId

from ..models.api_key_model import APIKey, KeyStatus


class RotationUrgency(Enum):
    """轮换紧急程度。"""
    LOW = "low"           # 30天后到期
    MEDIUM = "medium"     # 14天后到期
    HIGH = "high"         # 7天后到期
    CRITICAL = "critical" # 3天后到期或已过期


@dataclass
class RotationAlert:
    """轮换提醒数据。"""
    key_id: str
    user_id: str
    key_name: str
    provider: str
    created_at: datetime
    age_days: int
    urgency: RotationUrgency
    recommended_action: str
    alert_message: str


class KeyRotationChecker:
    """密钥轮换检查器。"""
    
    def __init__(self, mongodb_client: motor.motor_asyncio.AsyncIOMotorClient = None):
        """初始化轮换检查器。
        
        Args:
            mongodb_client: MongoDB客户端
        """
        self.mongodb = mongodb_client
        
        # 轮换策略配置 (天数)
        self.rotation_policies = {
            RotationUrgency.CRITICAL: 90,  # 90天为关键期
            RotationUrgency.HIGH: 83,      # 83天为高风险期 (7天前提醒)
            RotationUrgency.MEDIUM: 76,    # 76天为中风险期 (14天前提醒)
            RotationUrgency.LOW: 60        # 60天为低风险期 (30天前提醒)
        }
        
    async def check_rotation_status(self, key_id: Optional[str] = None) -> List[RotationAlert]:
        """检查密钥轮换状态。
        
        Args:
            key_id: 特定密钥ID，如果为None则检查所有密钥
            
        Returns:
            需要轮换的密钥列表
        """
        if not self.mongodb:
            return []
            
        try:
            db = self.mongodb.ai_writing
            
            # 构建查询条件
            query = {"status": {"$ne": KeyStatus.REVOKED.value}}
            if key_id:
                query["_id"] = ObjectId(key_id)
                
            # 查询所有活跃密钥
            cursor = db.api_keys.find(query)
            keys = await cursor.to_list(length=None)
            
            alerts = []
            current_time = datetime.utcnow()
            
            for key_doc in keys:
                api_key = APIKey.from_dict(key_doc)
                
                # 计算密钥年龄
                age_days = (current_time - api_key.created_at).days
                
                # 确定紧急程度
                urgency = self._determine_urgency(age_days)
                
                if urgency:  # 如果需要提醒
                    alert = RotationAlert(
                        key_id=str(api_key._id),
                        user_id=api_key.user_id,
                        key_name=api_key.key_name or f"{api_key.provider.value} Key",
                        provider=api_key.provider.value,
                        created_at=api_key.created_at,
                        age_days=age_days,
                        urgency=urgency,
                        recommended_action=self._get_recommended_action(urgency),
                        alert_message=self._generate_alert_message(api_key.key_name, urgency, age_days)
                    )
                    alerts.append(alert)
                    
            return alerts
            
        except Exception as e:
            print(f"轮换状态检查失败: {e}")
            return []
    
    def _determine_urgency(self, age_days: int) -> Optional[RotationUrgency]:
        """确定轮换紧急程度。
        
        Args:
            age_days: 密钥年龄(天)
            
        Returns:
            紧急程度，如果不需要提醒则返回None
        """
        if age_days >= self.rotation_policies[RotationUrgency.CRITICAL]:
            return RotationUrgency.CRITICAL
        elif age_days >= self.rotation_policies[RotationUrgency.HIGH]:
            return RotationUrgency.HIGH
        elif age_days >= self.rotation_policies[RotationUrgency.MEDIUM]:
            return RotationUrgency.MEDIUM
        elif age_days >= self.rotation_policies[RotationUrgency.LOW]:
            return RotationUrgency.LOW
        else:
            return None
    
    def _get_recommended_action(self, urgency: RotationUrgency) -> str:
        """获取推荐操作。
        
        Args:
            urgency: 紧急程度
            
        Returns:
            推荐操作描述
        """
        actions = {
            RotationUrgency.CRITICAL: "立即轮换密钥 - 密钥已过期或即将过期",
            RotationUrgency.HIGH: "计划在7天内轮换密钥",
            RotationUrgency.MEDIUM: "计划在14天内轮换密钥",
            RotationUrgency.LOW: "考虑在30天内轮换密钥"
        }
        return actions[urgency]
    
    def _generate_alert_message(self, key_name: str, urgency: RotationUrgency, age_days: int) -> str:
        """生成提醒消息。
        
        Args:
            key_name: 密钥名称
            urgency: 紧急程度
            age_days: 密钥年龄
            
        Returns:
            提醒消息
        """
        if urgency == RotationUrgency.CRITICAL:
            return f"🔴 关键提醒：密钥 '{key_name}' 已使用 {age_days} 天，强烈建议立即轮换。"
        elif urgency == RotationUrgency.HIGH:
            return f"🟠 高优先级：密钥 '{key_name}' 已使用 {age_days} 天，建议在7天内轮换。"
        elif urgency == RotationUrgency.MEDIUM:
            return f"🟡 中优先级：密钥 '{key_name}' 已使用 {age_days} 天，建议在14天内轮换。"
        else:  # LOW
            return f"🟢 低优先级：密钥 '{key_name}' 已使用 {age_days} 天，可考虑轮换。"
    
    async def create_rotation_reminder(self, alert: RotationAlert) -> bool:
        """创建轮换提醒记录。
        
        Args:
            alert: 轮换提醒
            
        Returns:
            是否成功创建
        """
        if not self.mongodb:
            return False
            
        try:
            db = self.mongodb.ai_writing
            
            # 检查是否已存在类似提醒(24小时内)
            recent_time = datetime.utcnow() - timedelta(hours=24)
            existing = await db.rotation_reminders.find_one({
                "key_id": alert.key_id,
                "urgency": alert.urgency.value,
                "created_at": {"$gte": recent_time}
            })
            
            if existing:
                return False  # 避免重复提醒
                
            # 创建提醒记录
            reminder_doc = {
                "key_id": alert.key_id,
                "user_id": alert.user_id,
                "key_name": alert.key_name,
                "provider": alert.provider,
                "urgency": alert.urgency.value,
                "age_days": alert.age_days,
                "alert_message": alert.alert_message,
                "recommended_action": alert.recommended_action,
                "created_at": datetime.utcnow(),
                "is_read": False,
                "is_dismissed": False
            }
            
            await db.rotation_reminders.insert_one(reminder_doc)
            return True
            
        except Exception as e:
            print(f"创建轮换提醒失败: {e}")
            return False
    
    async def get_user_reminders(self, user_id: str, include_dismissed: bool = False) -> List[Dict[str, Any]]:
        """获取用户的轮换提醒。
        
        Args:
            user_id: 用户ID
            include_dismissed: 是否包含已忽略的提醒
            
        Returns:
            提醒列表
        """
        if not self.mongodb:
            return []
            
        try:
            db = self.mongodb.ai_writing
            
            query = {"user_id": user_id}
            if not include_dismissed:
                query["is_dismissed"] = False
                
            cursor = db.rotation_reminders.find(query).sort("created_at", -1)
            reminders = await cursor.to_list(length=None)
            
            # 转换ObjectId为字符串
            for reminder in reminders:
                reminder["_id"] = str(reminder["_id"])
                
            return reminders
            
        except Exception as e:
            print(f"获取用户提醒失败: {e}")
            return []
    
    async def dismiss_reminder(self, reminder_id: str, user_id: str) -> bool:
        """忽略提醒。
        
        Args:
            reminder_id: 提醒ID
            user_id: 用户ID
            
        Returns:
            是否成功忽略
        """
        if not self.mongodb:
            return False
            
        try:
            db = self.mongodb.ai_writing
            
            result = await db.rotation_reminders.update_one(
                {"_id": ObjectId(reminder_id), "user_id": user_id},
                {"$set": {"is_dismissed": True, "dismissed_at": datetime.utcnow()}}
            )
            
            return result.modified_count > 0
            
        except Exception as e:
            print(f"忽略提醒失败: {e}")
            return False
    
    async def mark_reminder_read(self, reminder_id: str, user_id: str) -> bool:
        """标记提醒为已读。
        
        Args:
            reminder_id: 提醒ID
            user_id: 用户ID
            
        Returns:
            是否成功标记
        """
        if not self.mongodb:
            return False
            
        try:
            db = self.mongodb.ai_writing
            
            result = await db.rotation_reminders.update_one(
                {"_id": ObjectId(reminder_id), "user_id": user_id},
                {"$set": {"is_read": True, "read_at": datetime.utcnow()}}
            )
            
            return result.modified_count > 0
            
        except Exception as e:
            print(f"标记已读失败: {e}")
            return False


class RotationScheduler:
    """轮换提醒调度器。"""
    
    def __init__(self, checker: KeyRotationChecker):
        """初始化调度器。
        
        Args:
            checker: 轮换检查器
        """
        self.checker = checker
        self._scheduler_task = None
        
    async def start_scheduler(self):
        """启动调度器。"""
        if not self._scheduler_task:
            self._scheduler_task = asyncio.create_task(self._scheduler_loop())
            
    async def stop_scheduler(self):
        """停止调度器。"""
        if self._scheduler_task:
            self._scheduler_task.cancel()
            try:
                await self._scheduler_task
            except asyncio.CancelledError:
                pass
                
    async def _scheduler_loop(self):
        """调度器循环。"""
        while True:
            try:
                # 每天运行一次检查
                await asyncio.sleep(86400)  # 24小时
                await self.run_daily_check()
            except asyncio.CancelledError:
                break
            except Exception as e:
                print(f"调度器错误: {e}")
                await asyncio.sleep(3600)  # 出错后1小时后重试
                
    async def run_daily_check(self):
        """执行每日检查。"""
        try:
            # 检查所有密钥
            alerts = await self.checker.check_rotation_status()
            
            # 为每个提醒创建记录
            for alert in alerts:
                await self.checker.create_rotation_reminder(alert)
                
            if alerts:
                print(f"生成了 {len(alerts)} 个轮换提醒")
                
        except Exception as e:
            print(f"每日检查失败: {e}")
    
    async def force_check(self, key_id: Optional[str] = None) -> List[RotationAlert]:
        """强制执行检查。
        
        Args:
            key_id: 特定密钥ID
            
        Returns:
            检查结果
        """
        return await self.checker.check_rotation_status(key_id)


# 全局实例
rotation_checker = KeyRotationChecker()
rotation_scheduler = RotationScheduler(rotation_checker)


async def rotate_key_workflow(key_id: str, new_api_key: str) -> Dict[str, Any]:
    """密钥轮换工作流。
    
    Args:
        key_id: 要轮换的密钥ID
        new_api_key: 新的API密钥
        
    Returns:
        轮换结果
    """
    if not rotation_checker.mongodb:
        return {"success": False, "error": "数据库连接不可用"}
        
    try:
        db = rotation_checker.mongodb.ai_writing
        
        # 获取原密钥
        old_key_doc = await db.api_keys.find_one({"_id": ObjectId(key_id)})
        if not old_key_doc:
            return {"success": False, "error": "密钥不存在"}
            
        old_key = APIKey.from_dict(old_key_doc)
        
        # 加密新密钥
        from ..security.encryption import KeyEncryptor
        encryptor = KeyEncryptor()
        encrypted_new_key = encryptor.encrypt(new_api_key)
        
        # 更新密钥
        result = await db.api_keys.update_one(
            {"_id": ObjectId(key_id)},
            {
                "$set": {
                    "encrypted_key": encrypted_new_key,
                    "key_hash": encryptor._generate_hash(new_api_key),
                    "last_rotated_at": datetime.utcnow(),
                    "rotation_count": old_key.metadata.get("rotation_count", 0) + 1
                }
            }
        )
        
        if result.modified_count > 0:
            # 记录轮换历史
            history_doc = {
                "key_id": key_id,
                "user_id": old_key.user_id,
                "rotated_at": datetime.utcnow(),
                "previous_key_hash": old_key.key_hash,
                "rotation_reason": "scheduled_rotation",
                "success": True
            }
            await db.rotation_history.insert_one(history_doc)
            
            # 清除相关提醒
            await db.rotation_reminders.update_many(
                {"key_id": key_id, "is_dismissed": False},
                {"$set": {"is_dismissed": True, "dismissed_reason": "key_rotated"}}
            )
            
            return {"success": True, "message": "密钥轮换成功"}
        else:
            return {"success": False, "error": "密钥更新失败"}
            
    except Exception as e:
        return {"success": False, "error": f"轮换失败: {str(e)}"}